package query;

import org.apache.lucene.search.BooleanQuery;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import lucene.ClassifyQuery;
import lucene.ImportantWords;
import lucene.IndexWrapperG;
import net.sf.jclec.IConfigure;
import net.sf.jclec.IFitness;
import net.sf.jclec.IIndividual;
import net.sf.jclec.base.AbstractEvaluator;
import net.sf.jclec.fitness.SimpleValueFitness;
import net.sf.jclec.fitness.ValueFitnessComparator;
import net.sf.jclec.intarray.*;

import org.apache.lucene.search.TotalHitCountCollector;
import org.apache.lucene.search.spans.SpanFirstQuery;
import org.apache.lucene.search.spans.SpanTermQuery;
import org.apache.commons.configuration.Configuration;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;

public class SpanF4 extends AbstractEvaluator implements IConfigure {
	// ///////////////////////////////////////////////////////////////
	// --------------------------------------- Serialization constant
	// ///////////////////////////////////////////////////////////////

	/** Generated by Eclipse */

	private static final long serialVersionUID = -2635335580011827514L;

	// ///////////////////////////////////////////////////////////////
	// --------------------------------------------------- Properties
	// ///////////////////////////////////////////////////////////////

	/** Maximize of minimize functions? */

	protected boolean maximize = true;

	/** Distances matrix */


	private String[] wordArray;

	private IndexSearcher searcher = IndexWrapperG.getInstance()
			.getIndexSearcher();

	// ///////////////////////////////////////////////////////////////
	// ---------------------------------------------- Class variables
	// ///////////////////////////////////////////////////////////////

	private Comparator<IFitness> COMPARATOR;


	// ///////////////////////////////////////////////////////////////
	// ------------------------------------------------- Constructors
	// ///////////////////////////////////////////////////////////////
	/**
	 * Empty constructor.
	 */
	public SpanF4() {
		super();
	}

	// ///////////////////////////////////////////////////////////////
	// ------------------------------- Setting and getting properties
	// ///////////////////////////////////////////////////////////////

	/**
	 * Is this evaluator being used to maximize a function?
	 * 
	 * @return true if evaluator is used to maximize function, false otherwise.
	 */
	public boolean isMaximize() {
		return maximize;
	}

	/**
	 * Set the maximize flag.
	 * 
	 * @param maximize
	 *            Actual maximize flag.
	 */
	public void setMaximize(boolean maximize) {
		this.maximize = maximize;
	}

	// ///////////////////////////////////////////////////////////////
	// ------------------------ Overwriting AbstractEvaluator methods
	// ///////////////////////////////////////////////////////////////

	protected void evaluate(IIndividual ind) {
		// Individual genotype
		int[] genotype = ((IntArrayIndividual) ind).getGenotype();
		// use sorted map to remove redundant elements and improve readability
		Map<String, Integer> spanFirstMap = new HashMap<String, Integer>();

	//	double distance = 0;
		int positiveMatch = 0, negativeMatch = 0;

		// create query from Map
		BooleanQuery query = new BooleanQuery(true);

		// read through vector 2 ints at at time. 1st int retrieves word, second
		// specifies end for Lucene spanFirstQuery
		// store results in Map after removing redundant queries (i.e. same word
		// but lower end value)
		for (int i = 0; i < (genotype.length - 1); i = i + 2) {

			// any ints below 0 are ignored
			if (genotype[i] < 0 ||
			// ignore clauses where end value of spanFirst is very low
					genotype[i + 1] < 0)
				continue;

			int wordInd = 0;
			if (genotype[i] >= wordArray.length|| genotype[i] < 0)
				wordInd = 0;
			else
				wordInd = genotype[i];

			final String word = wordArray[wordInd];

			// if (spanFirstMap.containsKey(word)) {
			//
			// final int end = spanFirstMap.get(word);
			// spanFirstMap.put(word, Math.max(end,
			// intVectorIndividual.genome[x + 1]));
			// } else
			spanFirstMap.put(word, genotype[i + 1]);
		}
		
		
		for (String word : spanFirstMap.keySet()) {

			SpanFirstQuery sfq = new SpanFirstQuery(new SpanTermQuery(new Term(
					IndexWrapperG.FIELD_CONTENTS, word)),
					spanFirstMap.get(word));
			query.add(sfq, BooleanClause.Occur.SHOULD);
		}
	
		try {
			TotalHitCountCollector collector = new TotalHitCountCollector();
			searcher.search(query, IndexWrapperG.getInstance().catTrainF,
					collector);
			positiveMatch = collector.getTotalHits();
			
			collector = new TotalHitCountCollector();
			searcher.search(query, IndexWrapperG.getInstance().othersTrainF,
					collector);
			negativeMatch = collector.getTotalHits();
			
	
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		double F1train = ClassifyQuery.f1(positiveMatch, negativeMatch,
				IndexWrapperG.getInstance().totalTrainDocsInCat);
		
		//System.out.println("pos match " + positiveMatch + " neg match " + negativeMatch + " F1  " + F1train + " query " + query);

		ind.setFitness(new SimpleValueFitness(F1train));

	}

	public void configure(Configuration settings) {
	
		try {
			ImportantWords iw = new ImportantWords();
			wordArray = iw.getF1WordList(true);
			
			System.out.println(" IN CONFIGURE wordArray 0 -1  is " + wordArray[0] + " "+ wordArray[1]);
		} catch (IOException e) {
			System.out.println("Span4 execptions " + e);
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	// ///////////////////////////////////////////////////////////////
	// ---------------------------- Implementing IEvaluator interface
	// ///////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 */

	public Comparator<IFitness> getComparator() {
		// Set fitness comparator (if necessary)
		if (COMPARATOR == null)
			COMPARATOR = new ValueFitnessComparator(!maximize);

		// Return comparator
		return COMPARATOR;
	}
}